package com.cdx.rpc;

import com.cdx.rpc.config.RegistryConfig;
import com.cdx.rpc.config.RpcConfig;
import com.cdx.rpc.constant.RpcConstant;
import com.cdx.rpc.register.Registry;
import com.cdx.rpc.register.RegistryFactory;
import com.cdx.rpc.utils.ConfigUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * RPC 框架应用
 * 相当于 holder，存放了项目全局用到的变量。双检锁单例模式实现
 * <br>https://blog.csdn.net/weixin_44471490/article/details/108929289
 * @author donx
 * @create 2024-09-06 上午10:03
 */
@Slf4j
public class RpcApplication {
    /**
     * 在Java中，volatile关键字有两个主要用途：
     * 确保可见性：当一个线程修改了一个volatile变量的值，这个新值对于其他线程来说是立即可见的。这是因为对volatile变量的写操作会强制把缓存中的值刷新到主内存中，而读操作则会从主内存中获取最新值。
     * 禁止指令重排序：volatile变量的读写操作不会被编译器或处理器重排序。这意味着volatile变量的读写操作会按照代码中的顺序执行，这对于维护多线程程序的一致性至关重要。
     */
    private static volatile RpcConfig rpcConfig;

    /**
     * 框架初始化，支持传入自定义配置
     * @param newRpcConfig
     */
    public static void init(RpcConfig newRpcConfig) {
        rpcConfig = newRpcConfig;
        log.info("rpc init, config = {}", newRpcConfig.toString());
        // 注册中心初始化
        RegistryConfig registryConfig = rpcConfig.getRegistryConfig();
        Registry registry = RegistryFactory.getInstance(registryConfig.getRegistry());
        registry.init(registryConfig);
        log.info("registry init, config = {}", registryConfig);
        // 创建并注册 Shutdown Hook，JVM 退出时执行操作
        Runtime.getRuntime().addShutdownHook(new Thread(registry::destroy));
    }


    /**
     * 初始化
     */
    public static void init() {
        RpcConfig newRpcConfig;
        try {
            newRpcConfig = ConfigUtils.loadConfig(RpcConfig.class, RpcConstant.DEFAULT_CONFIG_PREFIX);
        }catch (Exception e) {
            // 配置加载失败，使用默认值
            newRpcConfig = new RpcConfig();
        }
        init(newRpcConfig);
    }
    /**
     * 获取配置
     *
     * @return
     */
    public static RpcConfig getRpcConfig() {
        if(rpcConfig == null) {
            synchronized (RpcApplication.class) {
                if(rpcConfig == null) {
                    init();
                }
            }
        }
        return rpcConfig;
    }

}
